////////////////////////////////////////////////////////////////////////////
// Portions Copyright (c) 2012 Kentaro Sekimoto  All rights reserved.
////////////////////////////////////////////////////////////////////////////

#include <tinyhal.h>
#include "..\FM3.h"

extern UINT32 ARM_Vectors[84];  // the interrupt vector table
extern UINT32 FAULT_SubHandler; // the standard fault handler

void CPU_INTC_Initialize()
{
    // disable all interrupts
    NVIC->ICER[0] = 0xFFFFFFFF;
    NVIC->ICER[1] = 0xFFFFFFFF;
    NVIC->ICER[2] = 0xFFFFFFFF;
    // clear pending bits
    NVIC->ICPR[0] = 0xFFFFFFFF;
    NVIC->ICPR[1] = 0xFFFFFFFF;
    NVIC->ICPR[2] = 0xFFFFFFFF;

#ifdef FIQ_SAMPLING_PROFILER
    ARM_Vectors[2]  = (UINT32)&FIQ_Handler + 1;      // NMI
#else
    ARM_Vectors[2]  = (UINT32)&FAULT_SubHandler + 1; // NMI
#endif
    ARM_Vectors[3]  = (UINT32)&FAULT_SubHandler + 1; // Hard Fault
    ARM_Vectors[4]  = (UINT32)&FAULT_SubHandler + 1; // MMU Fault
    ARM_Vectors[5]  = (UINT32)&FAULT_SubHandler + 1; // Bus Fault
    ARM_Vectors[6]  = (UINT32)&FAULT_SubHandler + 1; // Usage Fault
    ARM_Vectors[11] = (UINT32)&FAULT_SubHandler + 1; // SVC
    ARM_Vectors[12] = (UINT32)&FAULT_SubHandler + 1; // Debug
    ARM_Vectors[14] = (UINT32)&FAULT_SubHandler + 1; // PendSV
    ARM_Vectors[15] = (UINT32)&FAULT_SubHandler + 1; // Systick

    __DMB(); // ensure table is written

    SCB->AIRCR = (0x5FA << SCB_AIRCR_VECTKEY_Pos)   // unlock key
//              | (7 << SCB_AIRCR_PRIGROUP_Pos);    // no priority group bits
                | (3 << SCB_AIRCR_PRIGROUP_Pos);    // riority group 4 bits
    SCB->VTOR = (UINT32)ARM_Vectors;                // vector table base
    SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk         // enable faults
            | SCB_SHCSR_BUSFAULTENA_Msk
            | SCB_SHCSR_MEMFAULTENA_Msk;
}

BOOL CPU_INTC_ActivateInterrupt(UINT32 Irq_Index, HAL_CALLBACK_FPN ISR, void* ISR_Param)
{
    ARM_Vectors[Irq_Index + 16] = (UINT32)ISR;              // exception = irq + 16
    // assure table is written
    __DMB();
    NVIC->ICPR[Irq_Index >> 5] = 1 << (Irq_Index & 0x1F);   // clear pending bit
    NVIC->ISER[Irq_Index >> 5] = 1 << (Irq_Index & 0x1F);   // set enable bit
    return TRUE;
}

BOOL CPU_INTC_DeactivateInterrupt(UINT32 Irq_Index)
{
    NVIC->ICER[Irq_Index >> 5] = 1 << (Irq_Index & 0x1F);   // clear enable bit */
    return TRUE;
}

BOOL CPU_INTC_InterruptEnable(UINT32 Irq_Index)
{
    UINT32 ier = NVIC->ISER[Irq_Index >> 5];                // old state
    NVIC->ISER[Irq_Index >> 5] = 1 << (Irq_Index & 0x1F);   // set enable bit
    return (ier >> (Irq_Index & 0x1F)) & 1;                 // old enable bit
}

BOOL CPU_INTC_InterruptDisable(UINT32 Irq_Index)
{
    UINT32 ier = NVIC->ISER[Irq_Index >> 5];                // old state
    NVIC->ICER[Irq_Index >> 5] = 1 << (Irq_Index & 0x1F);   // clear enable bit
    return (ier >> (Irq_Index & 0x1F)) & 1;                 // old enable bit
}

BOOL CPU_INTC_InterruptEnableState(UINT32 Irq_Index)
{
    // return enabled bit
    return (NVIC->ISER[Irq_Index >> 5] >> (Irq_Index & 0x1F)) & 1;
}

BOOL CPU_INTC_InterruptState(UINT32 Irq_Index)
{
    // return pending bit
    return (NVIC->ISPR[Irq_Index >> 5] >> (Irq_Index & 0x1F)) & 1;
}

void CPU_INTC_Priority(UINT32 Irq_Index, UINT32 Irq_Pri)
{
    NVIC->IP[Irq_Index] = (UINT8)(Irq_Pri << 4);
}
